home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 March
/
EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso
/
earcd
/
util1
/
screnkys.lha
/
ScreenKeys.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-17
|
11KB
|
645 lines
/*
* ScreenKeys - A small and simple screen hotkey commodity.
*
* Public domain in 1995 by Magnus Holmgren.
*
* Written using the DICE compiler - no startup code.
*
* #define OS3 to get a somewhat smaller, OS 3.0+-specific version.
*/
#include <clib/alib_protos.h>
#include <clib/commodities_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/icon_protos.h>
#include <clib/utility_protos.h>
#include <exec/alerts.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <workbench/startup.h>
#include <string.h>
#define VERSION "1.2"
/******************** Global variables ********************/
struct DosLibrary *DOSBase;
struct Library *CxBase;
struct Library *IconBase;
struct IntuitionBase *IntuitionBase;
struct ExecBase *SysBase;
struct Library *UtilityBase;
struct MsgPort *CxPort;
struct WBStartup *WBMsg;
CxObj *Broker;
BOOL DoToBack;
/******************** Startup code ********************/
#ifdef OS3
#define MINVER 39
#else
#define MINVER 37
#endif
LONG Main( VOID );
__geta4 LONG
Startup( VOID )
{
LONG r;
SysBase = *( ( struct ExecBase ** ) 4 );
{
struct Process *thisTask = ( struct Process * ) FindTask( NULL );
if( !thisTask->pr_CLI )
{
/* Handle Workbench startup message */
struct MsgPort *port = &thisTask->pr_MsgPort;
WaitPort( port );
WBMsg = ( struct WBStartup * ) GetMsg( port );
}
}
SetSignal( 0, SIGBREAKF_CTRL_C );
if( SysBase->LibNode.lib_Version >= MINVER )
{
r = Main();
}
else
{
r = 100;
}
if( WBMsg )
{
Forbid();
ReplyMsg( ( struct Message * ) WBMsg );
}
return( r );
}
/******************** String constants ********************/
const TEXT Ver[] = "ScreenKeys " VERSION " (" __COMMODORE_DATE__ ")";
/* No localization yet... Would be quite easy to add though */
const TEXT MSG_ERRORTITLE[] = "ScreenKeys error";
const TEXT MSG_QUIT_GAD[] = "Quit";
const TEXT MSG_NO_MEM[] = "Not enough memory!";
const TEXT MSG_NO_LIB[] = "Couldn't open %s\nversion %ld or higher!";
const TEXT MSG_NO_PAT[] = "Couldn't parse pattern\n\"%s\"!";
const TEXT MSG_NO_SCR[] = "No hotkeys specified!";
const TEXT MSG_NO_ICON[] = "Couldn't open program icon!";
const TEXT MSG_NO_BROKER[] = "Couldn't create broker!";
const TEXT MSG_BAD_FILTER[] = "Bad input description:\n\"%s\"!";
const TEXT MSG_NO_CLI[] = "Shell start not yet supported\n";
const TEXT MSG_DESCRIPTION[] = "Provides hotkeys for screens";
/******************** Pool support ********************/
/* Note: For this to work with DICE, some assembler stubs are needed (basically
* "converting" the '@' prefix generated by DICE, to the '_' prefix in pools.lib.
* In the DMakeFile, this is handled by the miscsr.lib. Should be trivial to
* fix, if needed. Or you could change the prototypes to stack arguments, and use
* the Lib#? functions instead.
*/
APTR AsmCreatePool( __D0 ULONG, __D1 ULONG, __D2 ULONG, __A6 struct ExecBase * );
VOID AsmDeletePool( __A0 APTR, __A6 struct ExecBase * );
APTR AsmAllocPooled( __A0 APTR, __D0 ULONG, __A6 struct ExecBase * );
APTR AsmFreePooled( __A0 APTR, __A1 APTR, __D0 ULONG, __A6 struct ExecBase * );
APTR MemoryPool;
LONG
InitPool( VOID )
{
#ifdef OS3
return( ( LONG ) ( MemoryPool = CreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024 ) ) );
#else
return( ( LONG ) ( MemoryPool = AsmCreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024, SysBase ) ) );
#endif
}
VOID
FreePool( VOID )
{
if( MemoryPool )
{
#ifdef OS3
DeletePool( MemoryPool );
#else
AsmDeletePool( MemoryPool, SysBase );
#endif
MemoryPool = NULL;
}
}
APTR
MemAlloc( ULONG size )
{
APTR *mem;
size += 4;
#ifdef OS3
if( mem = AllocPooled( MemoryPool, size ) )
#else
if( mem = AsmAllocPooled( MemoryPool, size, SysBase ) )
#endif
{
*( ( ( ULONG * ) mem )++ ) = size;
}
return( mem );
}
/* Not used at the moment */
#ifdef MEM_FREE_NEEDED
VOID
MemFree( APTR mem )
{
if( mem )
{
ULONG size = *( --( ( ULONG * ) mem ) );
#ifdef OS3
FreePooled( MemoryPool, mem, size );
#else
AsmFreePooled( MemoryPool, mem, size, SysBase );
#endif
}
}
#endif
/******************** Misc ********************/
LONG
MyRequest( STRPTR title, STRPTR body, STRPTR gads, ... )
{
struct EasyStruct es;
es.es_StructSize = sizeof( es );
es.es_Flags = 0;
es.es_Title = title;
es.es_TextFormat = body;
es.es_GadgetFormat = gads;
return( EasyRequestArgs( NULL, &es, NULL, &gads + 1 ) );
}
VOID
ErrRequest( STRPTR body, ... )
{
MyRequest( MSG_ERRORTITLE, body, MSG_QUIT_GAD, &body + 1 );
}
VOID
MemError( VOID )
{
ErrRequest( MSG_NO_MEM );
}
struct Library *
OpenLib( STRPTR name, LONG ver )
{
struct Library *lib;
if( !( lib = OpenLibrary( name, ver ) ) )
{
ErrRequest( MSG_NO_LIB, name, ver );
}
return( lib );
}
/******************** Argument parsing ********************/
/* Convert string to caseless pattern. Shows error requesters. */
STRPTR
MakePattern( STRPTR str )
{
STRPTR pat;
LONG len = strlen( str ) * 2 + 2;
if( pat = MemAlloc( len ) )
{
if( ParsePatternNoCase( str, pat, len ) < 0 )
{
ErrRequest( MSG_NO_PAT, str );
pat = NULL;
}
}
else
{
MemError();
}
return( pat );
}
/* Make a hotkey for the specified screen. Screen will be used
* as the id (!), which makes the Commodity message loop very simple.
*/
CxObj *
MakeHotKey( STRPTR hotkey, STRPTR screen )
{
CxObj *hot;
if( hot = HotKey( hotkey, CxPort, ( LONG ) screen ) )
{
if( CxObjError( hot ) )
{
ErrRequest( MSG_BAD_FILTER, hotkey );
DeleteCxObj( hot );
hot = NULL;
}
}
else
{
MemError();
}
return( hot );
}
/* Parse a SCREENKEY tooltype */
BOOL
ParseHotKey( CxObj *broker, STRPTR arg )
{
struct CSource in;
TEXT buf[ 256 ];
LONG i;
BOOL ret = FALSE;
in.CS_Buffer = arg;
in.CS_Length = strlen( arg );
in.CS_CurChr = 0;
/* Maybe not used often, but it is quite handy.
* Similar to strtok, but with quote support.
*/
i = ReadItem( buf, sizeof( buf ), &in );
if( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) )
{
STRPTR screen;
LONG i;
#ifndef OS3
/* Fix ParsePatternNoCase bug */
for( screen = buf; *screen; ++screen )
{
*screen = ToUpper( *screen );
}
#endif
screen = MakePattern( buf );
while( ( i = ReadItem( buf, sizeof( buf ), &in ) ) == ITEM_EQUAL )
{
}
if( screen && ( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) ) )
{
CxObj *hotkey;
if( hotkey = MakeHotKey( buf, screen ) )
{
AttachCxObj( broker, hotkey );
ret = TRUE;
}
}
}
return( ret );
}
/* Get the CX_PRIORITY value */
LONG
GetCxPri( struct DiskObject *icon )
{
STRPTR str;
LONG val = 0;
if( str = FindToolType( icon->do_ToolTypes, "CX_PRIORITY" ) )
{
StrToLong( str, &val );
}
return( val );
}
/* Add hotkeys for the screens to the broker */
BOOL
AddHotKeys( CxObj *broker, struct DiskObject *icon )
{
STRPTR *args;
BOOL err = FALSE, keys = FALSE;
SetIoErr( 0 );
for( args = icon->do_ToolTypes; *args; ++args )
{
if( !Strnicmp( "SCREENKEY=", *args, 10 ) )
{
if( !ParseHotKey( broker, *args + 10 ) )
{
err = TRUE;
break;
}
else
{
keys = TRUE;
}
}
}
if( !( err || keys ) )
{
ErrRequest( MSG_NO_SCR );
return( FALSE );
}
else
{
return( !err );
}
}
/******************** Commodity support ********************/
struct NewBroker NewBroker =
{
NB_VERSION,
"ScreenKeys",
"ScreenKeys "VERSION,
MSG_DESCRIPTION,
NBU_UNIQUE, 0, 0,
NULL, 0
};
VOID
FreeBroker( VOID )
{
DeleteCxObjAll( Broker );
DeleteMsgPort( CxPort );
}
BOOL
InitBroker( VOID )
{
BOOL ret = FALSE;
if( IconBase = OpenLib( "icon.library", 37 ) )
{
struct DiskObject *icon;
BPTR oldDir;
oldDir = CurrentDir( WBMsg->sm_ArgList[ 0 ].wa_Lock );
if( icon = GetDiskObject( WBMsg->sm_ArgList[ 0 ].wa_Name ) )
{
NewBroker.nb_Pri = GetCxPri( icon );
DoToBack = ( BOOL ) FindToolType( icon->do_ToolTypes, "SCREENTOBACK" );
if( CxPort = NewBroker.nb_Port = CreateMsgPort() )
{
LONG err;
if( Broker = CxBroker( &NewBroker, &err ) )
{
ret = AddHotKeys( Broker, icon );
}
else if( err != CBERR_DUP )
{
ErrRequest( MSG_NO_BROKER );
}
}
FreeDiskObject( icon );
}
else
{
ErrRequest( MSG_NO_ICON );
}
CurrentDir( oldDir );
CloseLibrary( IconBase );
}
if( !ret )
{
FreeBroker();
}
return( ret );
}
VOID
HandleHotKey( STRPTR screen )
{
struct Screen *scr, *front;
ULONG lock = LockIBase( 0 );
if( front = IntuitionBase->FirstScreen )
{
for( scr = front->NextScreen; scr; scr = scr->NextScreen )
{
if( scr->Title && MatchPatternNoCase( screen, scr->Title ) )
{
/* So screen won't close "beneath" us */
Forbid();
UnlockIBase( lock );
ScreenToFront( scr );
if( DoToBack )
{
/* So cycling works as intended */
ScreenToBack( front );
}
Permit();
return;
}
}
}
UnlockIBase( lock );
}
BOOL
HandleCxPort( VOID )
{
CxMsg *msg;
BOOL run = TRUE;
while( msg = ( CxMsg * ) GetMsg( CxPort ) )
{
LONG id, type;
id = CxMsgID( msg );
type = CxMsgType( msg );
ReplyMsg( ( struct Message * ) msg );
switch( type )
{
case CXM_IEVENT:
HandleHotKey( ( STRPTR ) id );
break;
case CXM_COMMAND:
switch( id )
{
case CXCMD_DISABLE:
ActivateCxObj( Broker, FALSE );
break;
case CXCMD_ENABLE:
ActivateCxObj( Broker, TRUE );
break;
case CXCMD_KILL:
run = FALSE;
break;
}
break;
}
}
return( run );
}
/******************** Main program ********************/
VOID
MainLoop( VOID )
{
LONG cxMask = 1 << CxPort->mp_SigBit;
BOOL run = TRUE;
ActivateCxObj( Broker, TRUE );
while( run )
{
LONG sigs;
sigs = Wait( cxMask | SIGBREAKF_CTRL_C );
if( sigs & cxMask )
{
if( !HandleCxPort() )
{
run = FALSE;
}
}
if( sigs & SIGBREAKF_CTRL_C )
{
run = FALSE;
}
}
}
LONG
Main( VOID )
{
LONG ret = RETURN_FAIL;
if( DOSBase = ( struct DosLibrary * ) OpenLibrary( "dos.library", 37 ) )
{
if( WBMsg )
{
if( IntuitionBase = ( struct IntuitionBase * ) OpenLibrary( "intuition.library", 37 ) )
{
if( UtilityBase = OpenLib( "utility.library", 37 ) )
{
if( CxBase = OpenLib( "commodities.library", 37 ) )
{
if( InitPool() )
{
if( InitBroker() )
{
MainLoop();
FreeBroker();
}
FreePool();
}
else
{
MemError();
}
CloseLibrary( CxBase );
}
CloseLibrary( UtilityBase );
}
CloseLibrary( ( struct Library * ) IntuitionBase );
}
else
{
Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_Intuition );
}
}
else
{
PutStr( MSG_NO_CLI );
}
CloseLibrary( ( struct Library * ) DOSBase );
}
else
{
Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_DOSLib );
}
return( ret );
}